package com.idea.errorcode.processor;

import com.google.auto.service.AutoService;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: 沉香
 * @date: 2025/04/13
 * @description: 异常码处理器，主要用于生成异常码工具类
 */
@AutoService(Processor.class)
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ErrorCodeProcessor extends AbstractProcessor {

    private static final Pattern PATTERN = Pattern.compile("^[A-Z][a-z]*");

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv) {
        //收集所有实现IErrorCode接口的枚举
        Set<TypeElement> errorCodeEnums = findErrorCodeEnums(roundEnv);
        if (errorCodeEnums.isEmpty()) {
            return false;
        }
        //根据收集到的枚举生成元数据文件，用于后续异常码文档的生成
        generateErrorCodeMetadataFile(errorCodeEnums);
        // 生成异常码工具类
        generateErrorCodesClass(errorCodeEnums);
        return false;
    }

    private Set<TypeElement> findErrorCodeEnums(RoundEnvironment roundEnv) {
        Set<TypeElement> errorEnums = new HashSet<>();

        // 获取IErrorCode接口的类型元素
        TypeElement iErrorCodeType = processingEnv.getElementUtils()
                .getTypeElement("com.idea.errorcode.api.IErrorCode");

        // 遍历所有枚举类型元素
        for (Element element : roundEnv.getRootElements()) {
            // 1. 过滤枚举类型
            if (element.getKind() == ElementKind.ENUM) {
                TypeElement typeElement = (TypeElement) element;

                // 2. 检查是否实现IErrorCode接口
                if (implementsInterface(typeElement, iErrorCodeType)) {
                    errorEnums.add(typeElement);
                }
            }
        }
        return errorEnums;
    }

    /**
     * 检查类型是否实现指定接口
     */
    private boolean implementsInterface(TypeElement typeElement, TypeElement targetInterface) {
        // 获取类型工具
        Types typeUtils = processingEnv.getTypeUtils();

        // 遍历所有实现的接口
        for (TypeMirror interfaceType : typeElement.getInterfaces()) {
            // 擦除泛型信息后比较
            if (typeUtils.isSameType(
                    typeUtils.erasure(interfaceType),
                    targetInterface.asType()
            )) {
                return true;
            }
        }
        return false;
    }

    private void generateErrorCodesClass(Set<TypeElement> errorEnums) {
        try {
            // 1. 创建Java源文件（包名固定为 generated，避免冲突）
            JavaFileObject file = processingEnv.getFiler().createSourceFile("com.idea.errorcode.generated.$");

            try (Writer writer = file.openWriter()) {
                // 2. 生成包声明和导入语句
                writer.write("package com.idea.errorcode.generated;\n\n");
                generateImports(writer, errorEnums);
                // 3. 类声明
                writer.write("/**\n");
                writer.write(" * 自动生成的错误码注册中心\n");
                writer.write(" */\n");
                writer.write("public final class $ {\n\n");
                // 4. 生成字段
                generateFields(writer, errorEnums);
                writer.write("}\n");
            }
        } catch (Exception e) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.ERROR,
                    "生成ErrorCodes失败: " + e.getMessage()
            );
        }
    }

    /**
     * 生成导入语句
     */
    private void generateImports(Writer writer, Set<TypeElement> errorEnums) throws IOException {
        Set<String> importedPackages = new HashSet<>();

        // 收集所有枚举类所在包
        for (TypeElement enumElement : errorEnums) {
            String pkg = processingEnv.getElementUtils()
                    .getPackageOf(enumElement).getQualifiedName().toString();
            importedPackages.add(pkg);
        }

        // 生成 import 语句
        for (String pkg : importedPackages) {
            writer.write("import " + pkg + ".*;\n");
        }
        writer.write("\n");
    }

    /**
     * 生成静态字段
     */
    private void generateFields(Writer writer, Set<TypeElement> errorEnums) throws IOException {
        for (TypeElement enumElement : errorEnums) {
            String enumName = enumElement.getSimpleName().toString();

            // 遍历枚举常量
            for (Element elem : enumElement.getEnclosedElements()) {
                if (elem.getKind() == ElementKind.ENUM_CONSTANT) {
                    String constantName = elem.getSimpleName().toString();

                    // 字段命名规则：枚举类名_常量名（如ORDER_ERROR_NOT_FOUND）
                    String fieldName = enumName + "_" + constantName;
                    writer.write("    /**\n");
                    writer.write("     * " + enumElement.getQualifiedName() + "." + constantName + "\n");
                    writer.write("     */\n");
                    writer.write("    public static final " + enumName + " " + fieldName +
                            " = " + enumName + "." + constantName + ";\n\n");
                }
            }
        }
    }

    private void generateErrorCodeMetadataFile(Set<TypeElement> errorEnums) {
        try {
            // 创建资源文件
            Filer filer = processingEnv.getFiler();
            FileObject file = filer.createResource(
                    StandardLocation.CLASS_OUTPUT,
                    "",
                    "META-INF/error-codes",
                    errorEnums.toArray(new Element[0])
            );

            // 写入类名
            try (PrintWriter writer = new PrintWriter(file.openWriter())) {
                errorEnums.forEach(element ->
                        writer.println(element.getQualifiedName().toString())
                );
            }
        } catch (Exception e) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.ERROR,
                    "生成error-codes列表失败: " + e.getMessage()
            );
        }
    }

    public static String getFirstCamelWord(String str) {
        if (str == null || str.isEmpty()) {
            return "";
        }

        // 正则匹配第一个大写字母开头的小写字母序列
        Matcher matcher = PATTERN.matcher(str);
        return matcher.find() ? matcher.group() : "";
    }

}